`timescale 1ns/1ps
/*--------------------------------------------------------------------*\
FileName        : cbb_tiny_fifo.v
Author          ：hpy
Email           ：yuan_hp@qq.com
Date            ：2024年01月07日
Description     ：参数化可配置 fifo ，纯 verilog ，单个时钟

cbb_tiny_fifo#(
    .DATA_WIDTH (8)   ,  //数据宽度
    .ADDR_WIDTH (2)   ,  // fifo 存储 (1<<ADDR_WIDTH) -1  个数据 
    .ENABLE_RESET( 1) ,  // 1 生成 复位电路
    .ASYNC_OUT( 0 )      // 1 输出异步于时钟(re有效则输出有效) 
) u_tiny_fifo (
    .clk(clk) , 
    .reset(~rst_n) , 
    .we(we) , 
    .re(re) , 
    .i_data(din) , 
    .o_data() , 
    .o_valid() , 
    .full() , 
    .empty()   
);
\*--------------------------------------------------------------------*/
module cbb_tiny_fifo#(
    parameter DATA_WIDTH =8  ,//数据宽度
    parameter ADDR_WIDTH =2  ,   // fifo 存储的数量为 (1<<ADDR_WIDTH) - 1'b1 
    parameter ENABLE_RESET = 1 ,  // 1 生成 复位电路
    parameter ASYNC_OUT = 0       // 1 输出异步于时钟(re有效则输出有效) 
)(
    input                             clk , 
    input                             reset , 
    input                             we , 
    input                             re , 
    input       [DATA_WIDTH - 1 : 0 ] i_data , 
    output reg  [DATA_WIDTH - 1 : 0 ] o_data , 
    output reg                        o_valid , 
    output                            full , 
    output                            empty   
);

localparam  NUM = 1<<ADDR_WIDTH;


(* ram_style = "block" *) reg [DATA_WIDTH-1:0] mem [0:NUM-1] ;
reg [ADDR_WIDTH-1:0] wp  , rp  ;

generate 
    if(|ENABLE_RESET) begin 
        always @(posedge clk) begin 
            if(reset ) begin
                wp <= {(ADDR_WIDTH){1'b0}}  ;
                rp <= {(ADDR_WIDTH){1'b0}}  ;
            end else  begin
                if(we) wp <= wp + 1'b1 ; 
                if(re) rp <= rp + 1'b1 ;
            end 
        end 
    end else  begin
        always @(posedge clk) begin 
            if(we) wp <= wp + 1'b1 ; 
            if(re) rp <= rp + 1'b1 ;
        end        
    end
endgenerate 

generate 
    if(|ASYNC_OUT) begin : asyc_out_gen 
        always @(*) o_data  = mem[rp] ;
        always @(*) o_valid  = re ;
    end else begin 
        always @(posedge clk) o_data  <= mem[rp] ;
        always @(posedge clk) o_valid  <= re ? 1'b1 : 1'b0 ;
    end 
endgenerate  

always @(posedge clk) begin 
    if(we) mem[wp] <= i_data ;
end 

assign empty =  (we&(~re)) ? 1'b0:
                ((~we)&re) ? (wp==rp+1'b1) :
                wp==rp;


assign full =   (re & (~we)) ? 1'b0:
                ((~re) & we)? (rp == wp+1'b1+1'b1):
                rp==wp+1'b1;


endmodule 

